package FlowGraph.Transformations;

import java.util.*;

import antlr.collections.AST;
import antlr.*;

import FlowGraph.*;
import FlowGraph.Nodes.*;
import JavaGrammar.*;
import JavaGrammar.TreeScanners.NewExprExtracter;
import SymbolTable.*;
import FlowGraph.StatementInfo.*;
import util.*;
import db.ClassData;

//////////////////////////////////////////////////////////////////////////
//// NewStatementExtraction
/**

@author Ivan Jeukens
@version v 0.1 12/11/2002
*/
public class NewStatementExtraction extends Transformation {

    public NewStatementExtraction(FlowGraph fg, ClassData currentInfo) {
        super(fg);
        _currentInfo = currentInfo;
    }

    ///////////////////////////////////////////////////////////////////
    ////                        public  methods                    ////

    public void extractNewStatement(AST toextract, HashMap dontProcess,
            NewExprExtracter extracter, FlowGraphNode node) {
        _extractNewStatement(toextract, dontProcess, extracter, node);
    }

    public void extractNewDoStatement(AST toextract, HashMap dontProcess,
             NewExprExtracter extracter, FlowGraphNode node) {
        _extractNewDoStatement(toextract, dontProcess, extracter, node);
    }

    public void setNewVarCounter(int newvar) {
        _newvarCounter = newvar;
    }

    public int getNewVarCounter() {
        return _newvarCounter;
    }

    ///////////////////////////////////////////////////////////////////
    ////                        private methods                    ////

    private void _extractNewDoStatement(AST toextract, HashMap dontProcess,
             NewExprExtracter extracter, FlowGraphNode node) {
         try {
             extracter.statement(toextract);
         }
         catch(RecognitionException ex) {
             System.out.println("Extract New Expression : DO_CONDITION -> " +
                 ex);
         }
         LinkedList exprs = extracter.getNewExpressions();
         if(exprs.size() == 0) return;

         FlowGraphNode n = node.getInputNode(0);
         if(n.getType() == FlowGraphNode.BASIC_BLOCK) {
             BasicBlockNode bb = (BasicBlockNode) n;
             SymbolTable st = bb.getSymbolTable();
             SymbolTable parentST = null;
             if(st.getOwner() != bb) {
                 parentST = st;
                 st = new SymbolTable();
             }
             int size = bb.statementsSize();
             LinkedAST previousAST = (LinkedAST) bb.getStatement(size - 1);
             LinkedAST lastAST = (LinkedAST) previousAST.getNextSibling();
             for(int k = 0;k < exprs.size();k++) {
                 LinkedAST newexpr1 = _createNewExpr((LinkedAST)exprs.get(k));
                 bb.addStatement(newexpr1, size);

                 previousAST.setNextSibling(newexpr1);
                 newexpr1.setParent(previousAST);
                 previousAST = newexpr1;

                 VarDefStatementInfo vardef = new VarDefStatementInfo(bb, newexpr1);
                 vardef.setIsNew(true);
                 bb.setStatementInfo(vardef, size);

                 STLocalVariableEntry entry = STLocalVariableEntry.generateSTEntry(
                     newexpr1, _currentInfo.getName(), _currentInfo.getPackage(),
                     _currentInfo.getImports());
		 st.putElement(entry.getName(), entry);

                 size++;
             }
             if(st.getOwner() == null) {
                 SymbolTable.updateNodesST(bb, _flowGraph.getSink(),
                     st, parentST);
                 st.link(parentST);
                 st.setOwner(bb);
                 bb.setSymbolTable(st, true);
             }
             previousAST.setNextSibling(lastAST);
             lastAST.setParent(previousAST);
         }
         else {
             BasicBlockNode bb = new BasicBlockNode();
             bb.setVarDef(true);
             SymbolTable st = new SymbolTable();
             LinkedAST previousAST = null;
             for(int k = 0;k < exprs.size();k++) {
                 LinkedAST newexpr1 = _createNewExpr((LinkedAST)exprs.get(k));
                 bb.addStatement(newexpr1);

                 if(previousAST != null) previousAST.setNextSibling(newexpr1);
                 newexpr1.setParent(previousAST);
                 previousAST = newexpr1;

                 VarDefStatementInfo vardef = new VarDefStatementInfo(bb, newexpr1);
                 vardef.setIsNew(true);
                 bb.setStatementInfo(vardef, k);

                 STLocalVariableEntry entry = STLocalVariableEntry.generateSTEntry(
                     newexpr1, _currentInfo.getName(), _currentInfo.getPackage(),
                     _currentInfo.getImports());
		 st.putElement(entry.getName(), entry);
             }
             previousAST.setNextSibling(null);

             _addNodeBeforeDoCondition(bb, node, true);
             dontProcess.put(bb, null);
        }
    }
    
    private void _extractNewStatement(AST toextract, HashMap dontProcess,
             NewExprExtracter extracter, FlowGraphNode node) {
        if(toextract == null) return;

        try {
             extracter.statement(toextract);
        }
        catch(RecognitionException ex) {
             System.out.println("Extract New Statement : " + ex);
        }
        LinkedList exprs = extracter.getNewExpressions();
        if(exprs.size() == 0) return;

            /*if(n.getType() == FlowGraphNode.BASIC_BLOCK) {
                BasicBlockNode bb = (BasicBlockNode) n;
                SymbolTable st = bb.getSymbolTable();
                SymbolTable parentST = null;
                if(st.getOwner() != bb) {
                    parentST = st;
                    st = new SymbolTable();
                }
    
                int size = bb.statementsSize();
                LinkedAST previousAST = (LinkedAST) bb.getStatement(size - 1);
                LinkedAST lastAST = (LinkedAST) previousAST.getNextSibling();
                for(int k = 0;k < exprs.size();k++) {
                    LinkedAST newexpr1 = _createNewExpr((LinkedAST)exprs.get(k));
                    bb.addStatement(newexpr1, size);
    
                    previousAST.setNextSibling(newexpr1);
                    newexpr1.setParent(previousAST);
                    previousAST = newexpr1;
    
                    VarDefStatementInfo vardef = new VarDefStatementInfo(bb, newexpr1);
                    vardef.setIsNew(true);
                    bb.setStatementInfo(vardef, size);
    
                    STLocalVariableEntry entry = STLocalVariableEntry.generateSTEntry(
                        newexpr1, _currentInfo.getName(), _currentInfo.getPackage(),
                        _currentInfo.getImports());
                    st.putElement(entry.getName(), entry);
    
                    size++;
                }
                if(st.getOwner() == null) {
                    SymbolTable.updateNodesST(bb, _flowGraph.getSink() ,
                        st, parentST);
                    st.link(parentST);
                    st.setOwner(bb);
                    bb.setSymbolTable(st, true);
                }
                previousAST.setNextSibling(lastAST);
                lastAST.setParent(previousAST);
            }*/
            
            //else {

                 BasicBlockNode bb = new BasicBlockNode();
                 bb.setVarDef(true);
                 SymbolTable st = new SymbolTable();
                 LinkedAST previousAST = null;
                 for(int k = 0;k < exprs.size();k++) {
                     LinkedAST newexpr1 = _createNewExpr((LinkedAST)exprs.get(k));
                     bb.addStatement(newexpr1);
    
                     if(previousAST != null) previousAST.setNextSibling(newexpr1);
                     newexpr1.setParent(previousAST);
                     previousAST = newexpr1;
    
                     VarDefStatementInfo vardef = new VarDefStatementInfo(bb, newexpr1);
                     vardef.setIsNew(true);
                     bb.setStatementInfo(vardef, k);
    
                     STLocalVariableEntry entry = STLocalVariableEntry.generateSTEntry(
                         newexpr1, _currentInfo.getName(), _currentInfo.getPackage(),
                         _currentInfo.getImports());
                     st.putElement(entry.getName(), entry);
                 }
                 previousAST.setNextSibling(null);

                 _addNodeBefore(bb, st, node, true);
                 dontProcess.put(bb, null);

            //}
        
    }

    /* Cria um novo ast Type var1 = expr1 e substitui a entrada expr1 em
    expr2 por var1 */
    private LinkedAST _createNewExpr(LinkedAST expr1) {
        CommonToken tok = new CommonToken(JavaTokenTypes.VARIABLE_DEF, new String("VARIABLE_DEF"));
	LinkedAST vardef = new LinkedAST(tok);

        tok = new CommonToken(JavaTokenTypes.MODIFIERS, new String("MODIFIERS"));
	LinkedAST ast = new LinkedAST(tok);
	vardef.addChild(ast);
	ast.setParent(vardef);

	tok = new CommonToken(JavaTokenTypes.TYPE, new String("TYPE"));
	LinkedAST ast2 = new LinkedAST(tok);

	ast.setNextSibling(ast2);
	ast2.setParent(ast);

        NameCollector nc = new NameCollector();
        Util.inorderTraverse(expr1.getFirstChild(), nc);
        tok = new CommonToken(JavaTokenTypes.IDENT, nc.getName());
        LinkedAST ast3 = new LinkedAST(tok);
	
        ast2.addChild(ast3);
	ast3.setParent(ast2);

        String varname = new String("_newtmp" + _newvarCounter);
	tok = new CommonToken(JavaTokenTypes.IDENT, varname);
	LinkedAST ast4 = new LinkedAST(tok);

	ast2.setNextSibling(ast4);
	ast4.setParent(ast2);

        tok = new CommonToken(JavaTokenTypes.ASSIGN, "=");
        LinkedAST ast5 = new LinkedAST(tok);

        ast4.setNextSibling(ast5);
        ast5.setParent(ast4);

        tok = new CommonToken(JavaTokenTypes.EXPR, "EXPR");
        LinkedAST ast6 = new LinkedAST(tok);

        ast5.addChild(ast6);
        ast6.setParent(ast5);

        LinkedAST newexpr1 = Util.dupTree(expr1);
        ast6.addChild(newexpr1);
        newexpr1.setParent(ast6);

        expr1.setType(JavaTokenTypes.IDENT);
        expr1.setText(varname);
        expr1.setFirstChild(null);

        _newvarCounter++;

        return vardef;
    }

    ///////////////////////////////////////////////////////////////////
    ////                      private variables                    ////

    private int _newvarCounter;
    private ClassData _currentInfo;
    private FlowGraph _flowGraph;
}
